package cn.itsource.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.itsource.constants.Constants;
import cn.itsource.exception.GlobalException;
import cn.itsource.mapper.OrderMapper;
import cn.itsource.pojo.api.DriverResult;
import cn.itsource.pojo.app.bo.ConfirmBo;
import cn.itsource.pojo.app.bo.CustomerDetailBo;
import cn.itsource.pojo.app.bo.FlushCustomerBo;
import cn.itsource.pojo.app.vo.*;
import cn.itsource.pojo.bo.PayOrderBo;
import cn.itsource.pojo.bo.RuleStartBo;
import cn.itsource.pojo.domain.Order;
import cn.itsource.pojo.domain.OrderBill;
import cn.itsource.pojo.domain.OrderProfitsharing;
import cn.itsource.pojo.dto.RuleStartDto;
import cn.itsource.pojo.dto.RuleWaitDto;
import cn.itsource.pojo.dto.SharingDto;
import cn.itsource.pojo.vo.*;
import cn.itsource.result.R;
import cn.itsource.romate.api.DriverApi;
import cn.itsource.romate.api.PhoenixApi;
import cn.itsource.romate.api.RuleApi;
import cn.itsource.service.IOrderBillService;
import cn.itsource.service.IOrderProfitsharingService;
import cn.itsource.service.IOrderService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.consumer.PullStatus;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;





/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author beishan
 * @since 2024-04-10
 */
@Service
@Slf4j
@Transactional
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Autowired
    private RuleApi ruleApi;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private IOrderBillService orderBillService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private DefaultMQPullConsumer pullConsumer;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private PhoenixApi phoenixApi;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IOrderProfitsharingService profitsharingService;;

    @Autowired
    private DriverApi driverApi;

    /**
     * 支付单详情
     * @param orderNo
     * @return
     */
    @Override
    public CustomerDetailBo detail(String orderNo) {
        if (StrUtil.isEmpty(orderNo)) {
            throw new GlobalException("参数异常");
        }
        Order order = super.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNo, orderNo)
        );
        if (order == null) {
            throw new GlobalException("订单异常");
        }
        if(!Objects.equals(order.getStatus(), Constants.Order.UNPAID)){
            throw new GlobalException("订单异常");
        }
        OrderBill bill = orderBillService.getOne(new LambdaQueryWrapper<OrderBill>().eq(OrderBill::getOrderNo, orderNo));
        CustomerDetailBo customerDetailBo = new CustomerDetailBo();
        customerDetailBo.setDriverPhoto(order.getDriverPhoto());
        customerDetailBo.setDriverName(order.getDriverName());
        customerDetailBo.setDriverPhone(order.getDriverPhone());
        customerDetailBo.setStartPlace(order.getStartPlace());
        customerDetailBo.setEndPlace(order.getEndPlace());
        customerDetailBo.setOrderNo(order.getOrderNo());
        customerDetailBo.setCreateTime(order.getCreateTime());
        customerDetailBo.setFavourFee(order.getFavourAmount());
        customerDetailBo.setCarType(order.getCarType());
        customerDetailBo.setCarPlate(order.getCarPlate());


        customerDetailBo.setBaseMileage(bill.getBaseMileage());
        customerDetailBo.setBaseMileageAmount(bill.getBaseMileageAmount());
        customerDetailBo.setExceedBaseMileageEveryKmAmount(bill.getExceedBaseMileageAmount());
        customerDetailBo.setMileageAmount(bill.getMileageAmount());
        customerDetailBo.setWaitingMinute(bill.getWaitingMinute());
        customerDetailBo.setFreeBaseWaitingMinute(bill.getFreeBaseWaitingMinute());
        customerDetailBo.setExeceedBaseWaitingEveryKmAmount(bill.getExceedEveryMinuteAmount());
        customerDetailBo.setWaitingAmount(bill.getWaitingAmount());
        customerDetailBo.setRealMileage(order.getRealMileage());
        customerDetailBo.setFreeBaseReturnMileage(bill.getFreeBaseReturnMileage());
        customerDetailBo.setExceedBaseReturnEveryKmAmount(bill.getExceedBaseReturnEveryKmAmount());
        customerDetailBo.setReturnAmount(bill.getReturnAmont());
        customerDetailBo.setParkingAmount(bill.getParkingAmount());
        customerDetailBo.setTollAmount(bill.getTollAmount());
        customerDetailBo.setOtherAmount(bill.getOtherAmount());
        customerDetailBo.setTotalAmount(bill.getRealOrderAmount());
        customerDetailBo.setVoucherAmount(bill.getVoucherAmount());
        customerDetailBo.setRealPay(bill.getRealOrderAmount());
        customerDetailBo.setStatus(Constants.Order.UNPAID);

        return customerDetailBo;
    }

    /**
     * 推送订单
     * @param orderNo
     */
    @Override
    public void send(String orderNo) {
        if (StrUtil.isEmpty(orderNo)) {
            throw new GlobalException("参数异常");
        }
        Order order = super.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNo, orderNo)
                .eq(Order::getStatus,Constants.Order.DRIVER_CONFIRMATION_FEE)
        );
        if (order == null) {
            throw new GlobalException("订单异常");
        }

        //修改订单状态
        order.setStatus(Constants.Order.UNPAID);
        order.setUpdateTime(new Date());
        PayOrderBo payOrderBo = PayOrderBo.builder()
                .order_no(orderNo)
                .pay_user_id(order.getCustomerId())
                .amount(order.getRealOrderAmount())
                .subject(order.getRemark()).build();
        Message<PayOrderBo> message = MessageBuilder.withPayload(payOrderBo).build();


        TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction(
                "service-order",//事务监听器指定的名字
                "topic-payorder:tags-payorder", //目的地：topic:tags
                message,   //发给MQ的消息内容 Message对象
                order);//扩展参数 Object;  该参数会传递给事务监听器的arg

        log.info("事务消息发送结果 {} , {}",result.getLocalTransactionState() , result.getSendStatus() );


    }




    /**
     * 账单详情
     * @param orderNo
     * @return
     */
    @Override
    public DriverBillVo orderBill(String orderNo) {
        if (StrUtil.isEmpty(orderNo)) {
            throw new GlobalException("参数异常");
        }
        Order order = super.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNo, orderNo)
        );
        if (order == null) {
            throw new GlobalException("订单异常");
        }
        OrderBill bill = orderBillService.getOne(new LambdaQueryWrapper<OrderBill>()
                .eq(OrderBill::getOrderId, orderNo)
        );
        if (bill == null){
            throw new GlobalException("账单异常");
        }
        OrderProfitsharing profitsharing = profitsharingService.getOne(new LambdaQueryWrapper<OrderProfitsharing>()
                .eq(OrderProfitsharing::getOrderNo, orderNo)
        );
        if (profitsharing == null){
            throw new GlobalException("参数异常");
        }

        DriverBillVo billVo = new DriverBillVo();

        //里程相关参数
        billVo.setRealMileage(order.getRealMileage());
        billVo.setBaseMileagePrice(bill.getBaseMileageAmount());
        billVo.setBaseMileage(bill.getBaseMileage());
        billVo.setExceedMileagePrice(bill.getExceedBaseMileageAmount());
        billVo.setMileageFee(bill.getMileageAmount());
        //等时相关参数
        billVo.setWaitingMinute(bill.getWaitingMinute());
        billVo.setBaseWaitingMinute(bill.getFreeBaseWaitingMinute());
        billVo.setExceedWaitingMinutePrice(bill.getExceedEveryMinuteAmount());
        billVo.setWaitingFee(bill.getWaitingAmount());
        //返程相关参数
        billVo.setReturnMileage(order.getReturnMileage());
        billVo.setBaseReturnMileage(bill.getFreeBaseReturnMileage());
        billVo.setExceedBaseReturnMileagePrice(bill.getExceedBaseMileageAmount());
        billVo.setReturnFee(bill.getReturnAmont());
        //停车费
        billVo.setParkingFee(bill.getParkingAmount());
        //桥路费
        billVo.setTollFee(bill.getTollAmount());
        //其他费用
        billVo.setOtherFee(bill.getOtherAmount());
        //好处费
        billVo.setFavourFee(bill.getFavourAmount());
        //奖励费
        billVo.setIncentiveFee(bill.getIncentiveAmount());
        //总金额
        billVo.setTotalAmount(bill.getRealOrderAmount());
        //平台分账
        billVo.setPlatformIncome(profitsharing.getPlatformIncome());
        //平台分账比例
        billVo.setPlatformRate(profitsharing.getPlatformRate());
        //司机分账
        billVo.setDriverIncome(profitsharing.getDriverIncome());

        return billVo;
    }




    /**
     * 结束代驾
     * @param orderNo
     * @return
     */
    @Override
    public BigDecimal endDriving(String orderNo) {
        if (StrUtil.isEmpty(orderNo)) {
            throw new GlobalException("参数异常");
        }
        Order order = super.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNo, orderNo)
                .eq(Order::getStatus, Constants.Order.START_DRIVING)
        );
        if (order == null) {
            throw new GlobalException("订单异常");
        }

        OrderBill bill = orderBillService.getOne(new LambdaQueryWrapper<OrderBill>()
                .eq(OrderBill::getOrderId, orderNo)
        );
        if (bill == null){
            throw new GlobalException("账单异常");
        }

        //计算等时费
        //获取司机到达的时间
        Date arriveTime = order.getArriveTime();
        //获取司机开始代驾的时间
        Date startTime = order.getStartTime();
        long between = DateUtil.between(arriveTime, startTime, DateUnit.MINUTE);

        R r = ruleApi.ruleWait(between);
        if (!r.isSuccess()){
            throw new GlobalException(r.getMessage());
        }
        RuleWaitDto wait = (RuleWaitDto) r.getData();

        //计算真实里程费
        R r1 = phoenixApi.locationByOrderId(orderNo);
        if (!r1.isSuccess()){
            throw new GlobalException("计价失败");
        }
        List<RealPointVo> reals = (List<RealPointVo>) r1.getData();
        String url =  "https://apis.map.qq.com/ws/distance/v1/matrix/?mode=driving&from=%s&to=%s&key=%s";
        String key = "Z2HBZ-VWAWU-RRYVZ-GDL66-LGJH3-QOFTK";
        BigDecimal allDistance = BigDecimal.ZERO;
        for (int i = 0; i < reals.size() -1; i++) {
            RealPointVo startPoint = reals.get(i);
            RealPointVo endPoint = reals.get(i + 1);
            String mapUrl = String.format(url, startPoint.getLatitude() + "," + startPoint.getLongitude(), endPoint.getLatitude() + "," + endPoint.getLongitude(), key);
            ResponseEntity<String> forEntity = restTemplate.getForEntity(mapUrl, String.class);
            String body = forEntity.getBody();
            JSONObject jsonObject = JSONObject.parseObject(body);
            log.info("实际距离 {}",jsonObject);
            //取出返回体中的距离
            BigDecimal bigDecimal = jsonObject.getJSONObject("result").getJSONArray("rows").getJSONObject(0).getJSONArray("elements").getJSONObject(0).getBigDecimal("distance");
            //累加
            allDistance = allDistance.add(bigDecimal);

        }
        log.info("总距离 {}", allDistance);

        //统一单位 km
        BigDecimal divide = allDistance.divide(BigDecimal.valueOf(1000));
        //计算真实里程价格
        RuleStartBo ruleStartBo = ruleApi.ruleStartAdvance(new RuleStartDto(order.getStartTime(), divide));
        if(ruleStartBo == null){
            throw new GlobalException("计价失败");
        }
        //维护订单表
        Date date = new Date();
        //状态改为结束代驾
        order.setStatus(Constants.Order.END_DRIVING);
        order.setUpdateTime(date);
        //结束代驾时间
        order.setEndTime(date);
        //真实里程
        order.setRealMileage(divide);
        //返回里程
        order.setReturnMileage(divide);
        //真实金额
        order.setRealOrderAmount(ruleStartBo.getStart_advance());
        super.updateById(order);

        //维护账单表
        //免费等待时长
        bill.setFreeBaseWaitingMinute(wait.getFree_base_waiting_minute());
        //超出免费等待时长 每分钟价格
        bill.setExceedEveryMinuteAmount(wait.getExceed_every_minute_amount());

        //等待费用
        if (wait == null) {
            bill.setWaitingAmount(BigDecimal.ZERO);
        }
        bill.setWaitingAmount(wait.getDecimal());

        //里程费
        bill.setMileageAmount(ruleStartBo.getMileageAmount());
        //返程费
        bill.setReturnAmont(ruleStartBo.getReturnAmount());
        //修改时间
        bill.setUpdateTime(date);
        //等时时长
        bill.setWaitingMinute((int) between);
        //真实金额
        bill.setRealOrderAmount(ruleStartBo.getStart_advance());
        orderBillService.updateById(bill);

        return wait.getDecimal();
    }

    /**
     * 确认费用
     * @param confirmBo
     */
    @Override
    public void confirm(ConfirmBo confirmBo) {
        if (confirmBo == null) {
            throw new GlobalException("参数异常");
        }
        String orderNo = confirmBo.getOrderNo();
        if (StrUtil.isEmpty(orderNo)) {
            throw new GlobalException("参数异常");
        }
        Order order = super.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNo, orderNo)
                .eq(Order::getStatus, Constants.Order.END_DRIVING)
        );
        if (order == null) {
            throw new GlobalException("订单异常");
        }
        Date date = new Date();
        BigDecimal tollFee = confirmBo.getTollFee();
        BigDecimal parkingFee = confirmBo.getParkingFee();
        BigDecimal otherFree = confirmBo.getOtherFree();
        BigDecimal realOrderAmount = order.getRealOrderAmount();
        //确认费用后的价格
        BigDecimal addAll = realOrderAmount.add(tollFee).add(parkingFee).add(otherFree);

        //维护订单
        //修改订单状态
        order.setStatus(Constants.Order.DRIVER_CONFIRMATION_FEE);
        //修改真实价格
        order.setRealOrderAmount(addAll);
        //修改时间
        order.setUpdateTime(date);
        super.updateById(order);

        //维护账单
        OrderBill bill = orderBillService.getOne(new LambdaQueryWrapper<OrderBill>()
                .eq(OrderBill::getOrderId, order.getId())
        );
        if (bill == null){
            throw new GlobalException("账单异常");
        }
        //桥路费
        bill.setTollAmount(tollFee);
        //停车费
        bill.setParkingAmount(parkingFee);
        //其他费用
        bill.setOtherAmount(otherFree);
        //修改真实价格
        bill.setRealOrderAmount(addAll);
        //修改时间
        bill.setUpdateTime(date);
        orderBillService.updateById(bill);

        //平台分账计算
        OrderProfitsharing orderProfitsharing = new OrderProfitsharing();
        orderProfitsharing.setId(order.getId());
        orderProfitsharing.setOrderId(order.getId());
        orderProfitsharing.setOrderNo(orderNo);
        //远程调用driver 获取取消订单数和订单投诉数
        R<DriverResult> driverSummary = driverApi.getDriverSummary(order.getDriverId());
        if (!driverSummary.isSuccess() ){
            throw new GlobalException("调用司机信息失败");
        }
        DriverResult driverResult = driverSummary.getData();
        SharingDto sharingDto = new SharingDto();
        //总金额
        sharingDto.setAmount(addAll);
        //订单取消数
        sharingDto.setCancel(driverResult.getTodayCancel());
        //订单投诉数
        sharingDto.setComplain(driverResult.getTodayComplaint());
        //远程调用 rule
        R<SharingVo> sharing = ruleApi.sharing(sharingDto);
        if (!sharing.isSuccess() ){
            throw new GlobalException("调用规则失败");
        }
        SharingVo sharingVo = sharing.getData();
        //订单id
        orderProfitsharing.setOrderId(order.getId());
        //订单号
        orderProfitsharing.setOrderNo(order.getOrderNo());
        //总金额
        orderProfitsharing.setOrderAmount(addAll);
        //状态
        orderProfitsharing.setStatus(Constants.Order.UN_DIVIDE);
        //平台收益
        orderProfitsharing.setPlatformIncome(sharingVo.getPlatform_income());
        //司机收益
        orderProfitsharing.setDriverIncome(sharingVo.getDriver_income());
        //平台抽成比
        orderProfitsharing.setPlatformRate(sharingVo.getPlatform_rate());
        //司机分账比
        orderProfitsharing.setDriverRate(sharingVo.getDriver_rate());
        //司机微信
        orderProfitsharing.setToUserOpenId(String.valueOf(driverResult.getOpenId()));
        profitsharingService.save(orderProfitsharing);

    }

    /**
     * 根据状态回显信息
     * @return
     */
    @Override
    public FlushCustomerBo flush() {
        long id = StpUtil.getLoginIdAsLong();
        Order order = super.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getCustomerId, id)
                .in(Order::getStatus, Constants.Order.CUSTOMER_ORDER_IN_PROGRESS)
        );
        if (order == null) {
            return null;
        }
        return  FlushCustomerBo.builder().orderId(order.getId()).status(order.getStatus()).build();
    }

    /**
     * 开始代驾
     * @param orderNo
     */
    @Override
    public void startDriving(String orderNo) {
        if (StrUtil.isEmpty(orderNo)) {
            throw new GlobalException("参数异常");
        }
        Order order = super.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNo, orderNo)
                .eq(Order::getStatus, Constants.Order.DRIVER_ARRIVED)
        );
        if (order == null) {
            throw new GlobalException("订单异常");
        }

        //维护订单状态
        Date date = new Date();
        order.setStatus(Constants.Order.START_DRIVING);
        order.setUpdateTime(date);
        order.setStartTime(date);
        super.updateById(order);
    }

    /**
     * 获取redis中司机的位置
     * @param orderNo
     * @return
     */
    @Override
    public SharedDriverLocationVo pullDriverLocation(String orderNo) {
        String format = String.format(Constants.Redis.DRIVER_LOCATION_TO_REDIS_KEY,orderNo);
        return (SharedDriverLocationVo) redisTemplate.opsForValue().get(format);
    }


    /**
     * 实时将司机id 保存到redis
     * @param driverLocationVo
     */
    @Override
    public void location2driver(DriverLocationVo driverLocationVo) {
        String format = String.format(Constants.Redis.DRIVER_LOCATION_TO_REDIS_KEY,driverLocationVo.getOrderNo() );
        SharedDriverLocationVo sharedDriverLocationVo = new SharedDriverLocationVo();
        sharedDriverLocationVo.setLongitude( driverLocationVo.getLongitude() );
        sharedDriverLocationVo.setLatitude( driverLocationVo.getLatitude() );
        redisTemplate.opsForValue().set(format,sharedDriverLocationVo);
    }


    /**
     * 拉取订单状态
     * @param orderNo
     * @return
     */
    @Override
    public Boolean pullOrderStatus(String orderNo) {
        Order order = super.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNo, orderNo)
                .eq(Order::getStatus, Constants.Order.RECEIVED_ORDER)
        );
        if (order == null) {
            return false;
        }

        return Objects.equals(order.getStatus(), Constants.Order.RECEIVED_ORDER);
    }


    /**
     * 司乘同显
     * @param orderNo
     * @return
     */
    @Override
    public LocationVo location(String orderNo) {
        Order order = super.getById(orderNo);
        if (order == null) {
            return null;
        }
        LocationVo locationVo = new LocationVo();

        locationVo.setStatus(order.getStatus());
        locationVo.setStartPlaceLongitude(order.getStartPlaceLongitude());
        locationVo.setStartPlaceLatitude(order.getStartPlaceLatitude());
        locationVo.setEndPlaceLongitude(order.getEndPlaceLongitude());
        locationVo.setEndPlaceLatitude(order.getEndPlaceLatiude());

        return locationVo;
    }


    /**
     * 司机到达代驾点
     * @param orderNo
     * @return
     */
    @Override
    public void arrive2driver(String orderNo) {
        Order order = super.getById(orderNo);
        if (order == null) {
            throw new GlobalException("参数错误");
        }
        Date date = new Date();
        //修改订单状态
        order.setStatus(Constants.Order.DRIVER_ARRIVED);
        //添加司机到达代驾点的时间
        order.setArriveTime(date);
        order.setUpdateTime(date);
        super.updateById(order);
    }


    /**
     * 订单回显
     * @return
     */
    @Override
    public ExecuteOrderVo execute() {
        long customerId = StpUtil.getLoginIdAsLong();
        Order order = super.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getCustomerId,customerId )
                .in(Order::getStatus, Constants.Order.DRIVER_ORDER_IN_PROGRESS)
        );
        if (order == null) {
           return null;
        }
        //赋值
        ExecuteOrderVo executeOrderVo = new ExecuteOrderVo();
        executeOrderVo.setOrderNo(order.getOrderNo());
        executeOrderVo.setCustomerPhoto(order.getCustomerPhoto());
        executeOrderVo.setCustomerName(order.getCustomerName());
        executeOrderVo.setCustomerPhone(order.getCustomerPhone());
        executeOrderVo.setCustomerId(customerId);
        executeOrderVo.setStartPlace(order.getStartPlace());
        executeOrderVo.setStartLongitude(order.getStartPlaceLongitude());
        executeOrderVo.setStartLatitude(order.getStartPlaceLatitude());
        executeOrderVo.setEndPlace(order.getEndPlace());
        executeOrderVo.setEndLongitude(order.getEndPlaceLongitude());
        executeOrderVo.setEndLatitude(order.getStartPlaceLatitude());
        executeOrderVo.setFavourFee(order.getFavourAmount());
        executeOrderVo.setCarPlate(order.getCarPlate());
        executeOrderVo.setCarType(order.getCarType());
        executeOrderVo.setCreateTime(order.getCreateTime());
        executeOrderVo.setStatus(order.getStatus());

        return executeOrderVo;
    }


    /**
     * 取消订单
     * @param id
     */
    @Override
    public void change(String id) {
        Order order = super.getById(id);
        if (order == null) {
            throw new GlobalException("参数出错了");
        }
        if (Objects.equals(order.getStatus(), Constants.Order.RECEIVED_ORDER)){
            throw new GlobalException("订单已接单");
        }
        //违约金 TODO

        //修改订单状态
        order.setStatus(Constants.Order.CUSTOMER_CANCEL);
        super.updateById(order);
    }


    /**
     * 自动取消订单
     * @param id
     */
    @Override
    public void autochange(String id) {
        Order order = super.getById(id);
        if (order == null) {
            throw new GlobalException("参数出错了");
        }
        if (Objects.equals(order.getStatus(), Constants.Order.RECEIVED_ORDER)){
            throw new GlobalException("订单已接单");
        }

        //修改订单状态
        order.setStatus(Constants.Order.CUSTOMER_CANCEL);
        super.updateById(order);

    }



    /**
     * 司机抢单
     * @param id
     */
    @Override
    public void killOrder(String id) {

        //创建分布式锁
        RLock lock = redissonClient.getLock("lock-order" + id);
        try {
            //加上分布式锁，防止超卖
            lock.lock();
            //获取order
            Order order = super.getById(id);
            if (order == null) {
                throw new GlobalException("参数出错了");
            }
            if (!Objects.equals(order.getStatus(), Constants.Order.WAIT_ORDER)){
                throw new GlobalException("订单已经被抢了");
            }

            //将司机信息 填入order
            //获取司机信息
            Date date = new Date();
            long driverId = StpUtil.getLoginIdAsLong();
            SharedLoginVo loginVo = (SharedLoginVo) redisTemplate.opsForValue().get(String.format(Constants.Redis.REG_INFO, driverId));
            order.setDriverId(driverId);
            order.setDriverName(loginVo.getNickName());
            order.setDriverPhone(loginVo.getPhone());
            order.setDriverPhoto(loginVo.getAvatar());
            order.setUpdateTime(date);
            order.setAcceptTime(date);
            //修改订单状态 已接单
            order.setStatus(Constants.Order.RECEIVED_ORDER);

            super.updateById(order);
        } finally {
            //释放锁
            if(lock.isLocked())lock.unlock();
        }
    }



    /**
     * 司机拉取订单
     *
     */
    @Override
    public List<CreateOrderVo> pull2Order() {
        //获取 司机id
        long id = StpUtil.getLoginIdAsLong();

        //拼接
        try {
            //获取mq 中的结果
//            String a = Constants.RocketMQ.DRIVER_PULL_ORDER_TOPIC + ":" + String.format(Constants.RocketMQ.DRIVER_PULL_ORDER_TAGS, id);
            Set<MessageQueue> messageQueues = pullConsumer.fetchSubscribeMessageQueues(Constants.RocketMQ.DRIVER_PULL_ORDER_TOPIC);

            List<CreateOrderVo> createOrderVoList = new ArrayList<>();
            for (MessageQueue messageQueue : messageQueues) {
                //通过偏移量来获取消息 ：当前队列的消费位置
                long offset = pullConsumer.fetchConsumeOffset(messageQueue, true);

                //拉取消息，需要指定tags拼接司机ID， 来区分司机:
                String tags = String.format(Constants.RocketMQ.DRIVER_PULL_ORDER_TAGS, id);
                PullResult pullResult = pullConsumer.pull(messageQueue, tags, offset, 32);

                //找到消息
                if (pullResult != null && pullResult.getPullStatus().equals(PullStatus.FOUND)) {
                    //拿到消息列表
                    List<MessageExt> messageExtList = pullResult.getMsgFoundList();

                    if (messageExtList == null || messageExtList.size() == 0) continue;

                    for (MessageExt messageExt : messageExtList) {
                        //拿到消息内容，转换为订单对象
                        String message = new String(messageExt.getBody(), StandardCharsets.UTF_8);
                        CreateOrderVo orderMesssage = JSON.parseObject(message, CreateOrderVo.class);

                        //添加到结果列表
                        createOrderVoList.add(orderMesssage);
                        log.info("获取订单消息 {}", orderMesssage);
                    }
                }
                if(pullResult != null){
                    //重要：修改消息的消费位置，如果位置不后移，消息会一直被消费
                    pullConsumer.updateConsumeOffset(messageQueue,pullResult.getNextBeginOffset());
                }
            }
            return createOrderVoList;
        } catch (Exception e) {
            e.printStackTrace();
            throw new GlobalException("订单拉取失败");
        }
    }



    /**
     * 下单 维护 订单表和账单表
     * @param vo
     */
    @Override
    public List<CreateOrderVo> advance(AdvanceVo vo) {
        long customerId = StpUtil.getLoginIdAsLong();
        Order one = super.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getCustomerId, customerId)
                .eq(Order::getStatus, Constants.Order.ORDER_TOPIC)
        );
        //判断是否存在 支付的订单
        if (one != null) {
            throw new GlobalException("已有订单未支付");
        }
        Date date = new Date();
        RuleStartDto startDto = RuleStartDto.builder().startDate(date).mileage(vo.getExpectsMileage()).build();

        RuleStartBo ruleStartBoR = ruleApi.ruleStartAdvance(startDto);
        log.info("计算后的结果== {}", ruleStartBoR);


        //总金额 预估里程价格 + 返程价格
        BigDecimal startAdvance = ruleStartBoR.getStart_advance();

        //维护order表
        Order order = new Order();
        //生成订单号
        long id = IdUtil.createSnowflake(1, 1).nextId();
        order.setId(id);
        order.setOrderNo(String.valueOf(id));
        order.setCustomerId(customerId);
        order.setStartPlace(vo.getStartPlace());
        order.setEndPlace(vo.getEndPlace());
        order.setExpectsMileage(vo.getExpectsMileage());
        order.setExpectsOrderAmount(startAdvance);
        order.setCarPlate(vo.getCarPlate());
        order.setCarType(vo.getCarType());
        order.setStatus(0);
        order.setRemark("123456");
        order.setExpectMinutes(vo.getExpectMinutes());
        order.setStartPlaceLongitude(String.valueOf(vo.getStartPlaceLongitude()));
        order.setStartPlaceLatitude(String.valueOf(vo.getStartPlaceLatitude()));
        order.setEndPlaceLongitude(String.valueOf(vo.getEndPlaceLongitude()));
        order.setEndPlaceLatiude(String.valueOf(vo.getEndPlaceLatitude()));
        //乘客信息从redis 中获取
        String key = String.format(Constants.Redis.REG_INFO, customerId);
        SharedLoginVo o = (SharedLoginVo) redisTemplate.opsForValue().get(key);

        order.setCustomerName(o.getNickName());
        order.setCustomerPhone(o.getPhone());
        order.setCustomerPhoto(o.getAvatar());
        order.setCreateTime(new Date());
        super.saveOrUpdate(order);

        //维护账单表
        OrderBill orderBill = new OrderBill();
        orderBill.setId(id);
        orderBill.setOrderId(id);

        orderBill.setBaseMileage(ruleStartBoR.getBaseMileage());
        orderBill.setBaseMileageAmount(ruleStartBoR.getBaseMileageAmount());
        orderBill.setExceedBaseMileageAmount(ruleStartBoR.getExceedBaseMileageAmount());

        orderBill.setFreeBaseReturnMileage(ruleStartBoR.getFreeBaseReturnMileage());
        orderBill.setExceedBaseReturnEveryKmAmount(ruleStartBoR.getExceedBaseReturnEveryKmAmount());

        orderBill.setOrderNo(String.valueOf(id));

        orderBillService.save(orderBill);

        //搜索司机

        List<CreateOrderVo> createOrderVos = searchGeo(Constants.Redis.DRIVER_LOCATION_KEY, Double.parseDouble(String.valueOf(vo.getStartPlaceLongitude())), Double.parseDouble(String.valueOf(vo.getStartPlaceLatitude())), 50, 50L);
        log.info("司机列表 =={} " , createOrderVos);
        //司机列表
        for (CreateOrderVo createOrderVo : createOrderVos) {
            //开始地点
            createOrderVo.setStartAddress(vo.getStartPlace());
            //结束地点
            createOrderVo.setEndAddress(vo.getEndPlace());
            //里程数
            createOrderVo.setTotalMileage(vo.getExpectsMileage());
            //金额
            createOrderVo.setAmount(startAdvance);
            //订单id
            createOrderVo.setOrderId(String.valueOf(id));

            //使用mq 将订单推送给司机
            String a = Constants.RocketMQ.DRIVER_PULL_ORDER_TOPIC + ":" + String.format(Constants.RocketMQ.DRIVER_PULL_ORDER_TAGS,createOrderVo.getDriverId());
            Message<CreateOrderVo> message = MessageBuilder.withPayload(createOrderVo).build();
            SendResult sendResult = rocketMQTemplate.syncSend(a, message);
            log.info("MQ结果== {}", sendResult);


        }
        return createOrderVos;
    }



    /**
     * List<GeoSearchResult>
     * 坐标搜索
     * @param key ： 司机坐标的key
     * @param longitude ：中心点的经度
     * @param latitude ：中心点的维度
     * @param radius ：搜索的半径
     * @param limit ：匹配几个成员
     * @return ：命中的结果
     */
    public List<CreateOrderVo> searchGeo(String key, double longitude, double latitude, double radius, Long limit){
        List<CreateOrderVo> list = new ArrayList<>();
        CreateOrderVo createOrderVo = new CreateOrderVo();
        //指定中心坐标，千米为单位
        Circle circle = new Circle(new Point(longitude,latitude), new Distance(radius,Metrics.KILOMETERS));
        //GEO搜索的参数
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
        //结果中包含 距离
        args.includeDistance()
                //结果中包含坐标
                .includeCoordinates()
                //按照中心点距离近到远排序
                .sortAscending()
                //匹配前几个司机
                .limit(limit);
        GeoResults<RedisGeoCommands.GeoLocation<Object>> geoResults = redisTemplate.opsForGeo().radius(key, circle, args);
        //拿到GEO结果列表
        List<GeoResult<RedisGeoCommands.GeoLocation<Object>>> geoResultList = geoResults.getContent();
        //遍历结果
        for (GeoResult<RedisGeoCommands.GeoLocation<Object>> geoLocationGeoResult : geoResultList) {
            log.info("geo结果 =={}", geoLocationGeoResult);
            Distance distance = geoLocationGeoResult.getDistance();
            RedisGeoCommands.GeoLocation<Object> content = geoLocationGeoResult.getContent();
            Object name = content.getName();


            SettingVo setting = (SettingVo) redisTemplate.opsForValue().get(String.format(Constants.Redis.DRIVER_ONLINE_KEY, name));
            if (setting == null) {
                continue;
            }

            if (setting.getOrder_distance() < distance.getValue()) {
                continue;
            }
            if (setting.getRange_distance() < distance.getValue()) {
                continue;
            }
            //司机id
            createOrderVo.setDriverId(JSON.toJSONString(name) );
            //距离
            createOrderVo.setDriverDistance(BigDecimal.valueOf(distance.getValue()));



            list.add(createOrderVo);
        }
        return list;
    }
}
